package br.com.felix.easyclearcase.tasks;

import java.io.IOException;
import java.util.concurrent.Semaphore;
import br.com.felix.clearcase.command.ClearToolCommand;
import br.com.felix.commandline.SysCommandExecutor;
import br.com.felix.util.ILogDevice;

/**
 * Task that executes clearcase commands.
 * Because of cleartool limitations, clearcasetasks cannot be run in parallel.
 * They may be started in parallel, but a semaphore will make sure they run one at time.
 * @see Task
 * */
public class ClearCaseTask extends Task{

	protected static Semaphore clearTasksSemaphore = new Semaphore(1);
	
	protected ClearToolCommand clearToolCommand;
	
	protected boolean cancel = false;
	
	/**
	 * Logger that will be used to log what the class is doing.
	 * */
	protected ILogDevice logger;
	/**
	 * Logger that will log the command's execution's output. 
	 * */
	protected ILogDevice outputLogger;
	
	/**
	 * Instantiates a new clearcasetask to run the specified command.
	 * */
	public ClearCaseTask(ClearToolCommand cmd){
		this.clearToolCommand = cmd;
	}
	
	/**
	 * Instantiates a new clearcasetask to run the specified command, and to log the output on the specified outputlogger.
	 * */
	public ClearCaseTask(ClearToolCommand cmd, ILogDevice outputLogger){
		this.clearToolCommand = cmd;
		this.outputLogger = outputLogger;
	}
	
	
	@Override
	public void cancel() {
		cancel = true;
		changeStatus(TaskStatus.STOPPING);
	}

	

	@Override
	public final void run() {
		try {
			clearTasksSemaphore.acquire();
		}
		catch (InterruptedException e) {
			clearTasksSemaphore.release();
			changeStatus(TaskStatus.COMPLETE_FAIL);
			return;
		}
		//log("Starting clearcase task.");
		changeStatus(TaskStatus.IN_PROGRESS);
		String command = clearToolCommand.toCommandLine();
		SysCommandExecutor cmdexec = new SysCommandExecutor();
		if(clearToolCommand.getWorkingDirectory()!=null){
			String absolutePath = clearToolCommand.getWorkingDirectory().getAbsolutePath();
			cmdexec.setWorkingDirectory(absolutePath);
		}

		if(outputLogger==null){
			outputLogger = logger;
		}
		cmdexec.setOutputLogDevice(outputLogger);
		cmdexec.setErrorLogDevice(logger);
		try {
			if(cancel){
				changeStatus(TaskStatus.CANCELLED);
				return;
			}
			if(clearToolCommand.shouldExecute()){
				String executingCommandMsg = "Executing command '"+command+"'.";
				System.out.println(executingCommandMsg);
				log(executingCommandMsg);
				cmdexec.runCommand(command);
				
				if(logger.errorHasOcurred() || outputLogger.errorHasOcurred()){
					changeStatus(TaskStatus.COMPLETE_FAIL);
					log("Clearcase task completed with errors/warnings");
				}
				else{
					changeStatus(TaskStatus.COMPLETE_SUCCESS);
					log("Clearcase task completed successfully");
					clearToolCommand.commandExecutedSuccessfully();
				}
			}
			else{
				String skippingCommandMsg = "Skipping command '"+command+"'.";
				System.out.println(skippingCommandMsg);
				log(skippingCommandMsg);
				changeStatus(TaskStatus.CANCELLED);
			}
			
		}
		catch(IOException e){
			if(e.getMessage().contains("Cannot run program \"cleartool\"")){
				error("Error executing command '"+command+"'.",e);
				error("Could not run cleartool. Please verify that cleartool is in the PATH system variable.",e);
				changeStatus(TaskStatus.COMPLETE_FAIL);
			}
		}
		catch (Exception e) {
			error("Error executing command '"+command+"'.",e);
			changeStatus(TaskStatus.COMPLETE_FAIL);
		}
		finally{
			clearTasksSemaphore.release();
		}
	}


	
	protected void error(String string, Exception e) {
		if(logger!=null)logger.error(string, e);
	}


	protected void log(String string) {
		if(logger!=null){
			logger.log(string);
		}
	}


	public ILogDevice getLogger() {
		return logger;
	}


	
	public void setLogger(ILogDevice logger) {
		this.logger = logger;
	}


	@Override
	public TaskPriority getTaskPriority() {
		return TaskPriority.NORMAL;
	}


	
	public ILogDevice getOutputLogger() {
		return outputLogger;
	}


	
	public void setOutputLogger(ILogDevice outputLogger) {
		this.outputLogger = outputLogger;
	}

	@Override
	public boolean isToAddToReport() {
		return true;
	}
	
	public String toString(){
		return  clearToolCommand.getCommandName()+ " " + this.clearToolCommand.getFile().getAbsolutePath();
	}

}
